class Qilinx {
    constructor(){
        this.defaults={}; //全局默认参数配置
        this.beforeRequest=function(){}; //请求发送前的触发函数
        this.beforeResponse=function(){}; //请求响应到then/catch前触发函数
    };
    // 创建请求发送
    create(config){
        // 初始化defaults数据
        this._setDefault();
        // 初始化beforeRequest和beforeResponse
        if(typeof this.beforeRequest != "function"){
            this.beforeRequest=function(){};
        };
        if(typeof this.beforeResponse != "function"){
            this.beforeResponse=function(){};
        };
        // 校验config数据
        config=this._getValidateConfig(config);
        this.beforeRequest.apply(this,[config]);
        config.beforeRequest.apply(this,[config]);
        return new Promise((resolve,reject)=>{
            let xhr=new XMLHttpRequest(); //创建XMLHttpRequest对象
            if(config.dataType.toLocaleLowerCase() == "blob"){ //如果是媒体文件则设置responseType为blob
                xhr.responseType="blob";
            };
            // 监听请求状态变化事件
            xhr.onreadystatechange=()=>{
                if(xhr.readyState == 4){
                    config.complete.apply(this,[xhr]);
                    if(xhr.status == 200){
                        let res;
                        if(config.dataType.toLocaleLowerCase() == "json"){
                            try{
                                res=JSON.parse(xhr.responseText); //解析字符串形式的响应数据
                            }catch(error){
                                reject(error); //json解析失败
                            };
                        }else if(config.dataType.toLocaleLowerCase() == "xml"){
                            res=xhr.responseXML; //获取XML形式的响应数据
                        }else if(config.dataType.toLocaleLowerCase() == "html" || config.dataType == "string"){
                            res=xhr.responseText;
                        }else if(config.dataType.toLocaleLowerCase() == "blob"){
                            res=xhr.response;
                        }else{
                            res=xhr.responseText;
                        };
                        this.beforeResponse.apply(this,[xhr,res]);
                        config.beforeResponse.apply(this,[xhr,res]);
                        resolve(res);
                    }else if(xhr.status != 0){
                        this.beforeResponse.apply(this,[xhr]);
                        config.beforeResponse.apply(this,[xhr]);
                        reject(new Error("请求失败，状态码为"+xhr.status));
                    };
                }else if(xhr.readyState == 1){
                    config.beforeSend.apply(this,[xhr]); //请求发送之前
                };
            };
            // 监听超时处理
            xhr.ontimeout=()=>{
                this.beforeResponse.apply(this,[xhr]);
                config.beforeResponse.apply(this,[xhr]);
                reject(new Error("请求超时"+config.timeout+"ms"));
            };
            // 监听上传进度
            xhr.upload.onprogress=(e)=>{
                config.onProgress.apply(this,[e]);
            };

            if(config.dataType.toLocaleLowerCase() == "jsonp"){
                config.beforeSend.apply(this);
                // 创建script标签并加入到页面中
                let callbackName=("jsonp_"+Math.random()).replace(".","");
                let oHead=document.getElementsByTagName("head")[0];
                config.data[config.jsonpCallback]=callbackName;
                let oS=document.createElement("script");
                oHead.appendChild(oS);
                // 创建jsonp回调函数
                window[callbackName]=(result)=>{
                    config.complete.apply(this);
                    oHead.removeChild(oS);
                    clearTimeout(oS.timer);
                    window[callbackName]=null;
                    this.beforeResponse.apply(this,[result]);
                    config.beforeResponse.apply(this,[result]);
                    resolve(result);
                };
                // 发送请求
                if((config.baseUrl + config.url).indexOf("?") > -1 ){ // 若地址栏含有参数
                    oS.src=config.baseUrl+config.url+"&"+this._getParams(config.data);
                }else{ //若地址栏不含参数
                    oS.src=config.baseUrl+config.url+"?"+this._getParams(config.data);
                };
                // 超时处理
                oS.timer=setTimeout(()=>{
                    config.complete.apply(this);
                    window[callbackName]=null;
                    oHead.removeChild(oS);
                    this.beforeResponse.apply(this);
                    config.beforeResponse.apply(this);
                    reject(new Error("请求超时"+config.timeout+"ms"));
                },config.timeout);
            }else{
                if(["GET","DELETE"].includes(config.type.toLocaleUpperCase())){ //若是get或delete请求方式
                // if(config.type.toLocaleLowerCase() == "get"){ //若是get请求方式
                    if(this._getParams(config.data)){ //若携带数据参数
                        xhr.open(config.type.toLocaleUpperCase(),config.baseUrl+config.url+"?"+this._getParams(config.data),config.async);
                    }else{
                        xhr.open(config.type.toLocaleUpperCase(),config.baseUrl+config.url,config.async);
                    };
                    // 异步才设置超时时间
                    if(config.async){
                        xhr.timeout=config.timeout; //设置超时时间
                    };
                    // 添加配置的请求头
                    for(let item in config.headers){
                        xhr.setRequestHeader(item,config.headers[item]);
                    };
                    // 添加contentType
                    if(typeof config.contentType == "string"){
                        xhr.setRequestHeader("Content-Type",config.contentType);
                    };
                    xhr.withCredentials=config.withCredentials;
                    xhr.send(null);
                }else if(["POST","PUT","PATCH"].includes(config.type.toLocaleUpperCase())){
                // }else if(config.type.toLocaleLowerCase() == "post"){
                    xhr.open(config.type.toLocaleUpperCase(),config.baseUrl+config.url,config.async);
                    // 异步才设置超时时间
                    if(config.async){
                        xhr.timeout=config.timeout; //设置超时时间
                    };
                    // 添加配置的请求头
                    for(let item in config.headers){
                        xhr.setRequestHeader(item,config.headers[item]);
                    };
                    // 添加contentType
                    if(typeof config.contentType == "string"){
                        xhr.setRequestHeader("Content-Type",config.contentType);
                    };
                    if(config.processData){
                        config.data=this._getParams(config.data); //转换成序列化参数
                    };
                    xhr.withCredentials=config.withCredentials;
                    xhr.send(config.data);
                };
                const abort=function(){
                    xhr.abort();
                };
                config.cancelRequest.apply(this,[abort]);
            };
        });
    };
    // 设置全局默认数据
    _setDefault(){
        // 若defaults非对象，则默认为空对象
        if(typeof this.defaults != "object"){
            this.defaults={};
        };
        // baseUrl 基本路径
        if(typeof this.defaults.baseUrl != "string"){
            this.defaults.baseUrl="";
        };
        // url 路径
        if(typeof this.defaults.url != "string"){
            this.defaults.url="";
        };
        // data 请求数据
        if(typeof this.defaults.data != "object"){
            this.defaults.data={};
        };
        // type 请求方式post/get
        // if(typeof this.defaults.type != "string" || 
        //     (this.defaults.type.toLocaleUpperCase() != "POST" && this.defaults.type.toLocaleUpperCase() != "GET")
        // ){
        //     this.defaults.type="GET";
        // };
        if(typeof this.defaults.type != "string" || 
            (!["GET","POST","DELETE","PUT","PATCH"].includes(this.defaults.type.toLocaleUpperCase()))
        ){
            this.defaults.type="GET";
        };
        // timeout 请求超时时间
        if(typeof this.defaults.timeout != "number" || isNaN(this.defaults.timeout)){
            this.defaults.timeout=8000;
        };
        // dataType 返回参数类型
        if(typeof this.defaults.dataType != "string" || (
            this.defaults.dataType.toLocaleUpperCase() != "STRING" &&
            this.defaults.dataType.toLocaleUpperCase() != "XML" &&
            this.defaults.dataType.toLocaleUpperCase() != "HTML" &&
            this.defaults.dataType.toLocaleUpperCase() != "JSON" &&
            this.defaults.dataType.toLocaleUpperCase() != "BLOB" &&
            this.defaults.dataType.toLocaleUpperCase() != "JSONP"
        )){
            this.defaults.dataType="JSON";
        };
        // jsonpCallback 跨域回调方法名称
        if(typeof this.defaults.jsonpCallback != "string"){
            this.defaults.jsonpCallback="callback";
        };
        // headers 请求头配置
        if(typeof this.defaults.headers != "object"){
            this.defaults.headers={};
        };
        // contentType 配置
        if(typeof this.defaults.contentType != "string" && this.defaults.contentType !== false){
            this.defaults.contentType="application/x-www-form-urlencoded";
        };
        // processData 配置
        if(typeof this.defaults.processData != "boolean"){
            this.defaults.processData=true;
        };
        // cache 缓存配置
        if(typeof this.defaults.cache != "boolean"){
            this.defaults.cache=true;
        };
        // async 异步
        if(typeof this.defaults.async != "boolean"){
            this.defaults.async=true;
        };
        // withCredentials 跨站点访问控制
        if(typeof this.defaults.withCredentials != "boolean"){
            this.defaults.withCredentials=false;
        };
        // beforeSend 请求发送前
        if(typeof this.defaults.beforeSend != "function"){
            this.defaults.beforeSend=function(){};
        };
        // complete 请求完成
        if(typeof this.defaults.complete != "function"){
            this.defaults.complete=function(){};
        };
        // onProgress 请求进度
        if(typeof this.defaults.onProgress != "function"){
            this.defaults.onProgress=function(){};
        };
        // cancelRequest 取消请求
        if(typeof this.defaults.cancelRequest != "function"){
            this.defaults.cancelRequest=function(){};
        };
        // beforeRequest 请求发送前对数据处理的方法
        if(typeof this.defaults.beforeRequest != "function"){
            this.defaults.beforeRequest=function(){};
        };
        // beforeResponse 请求发送响应前处理结果的方法
        if(typeof this.defaults.beforeResponse != "function"){
            this.defaults.beforeResponse=function(){};
        };
    };
    // 对create的参数config进行初始化，获取初始化后的config
    _getValidateConfig(config){
        // 若config非对象，则默认为defaults
        if(typeof config != "object"){
            config={};
            Object.assign(config,this.defaults);
        };
        // baseUrl 基本路径
        if(typeof config.baseUrl != "string"){
            config.baseUrl=this.defaults.baseUrl;
        };
        // url 路径
        if(typeof config.url != "string"){
            config.url=this.defaults.url;
        };
        // data 请求数据
        if(typeof config.data != "object"){
            config.data=this.defaults.data;
        }else{ //如果配置的config有data则将defaults中的追加进来
            let obj=config.data;
            config.data={};
            Object.assign(config.data,this.defaults.data,obj);
        };
        // type 请求方式post/get
        // if(typeof config.type != "string" || (
        //     config.type.toLocaleUpperCase() != "POST" && config.type.toLocaleUpperCase() != "GET"
        // )){
        //     config.type=this.defaults.type;
        // };
        if(typeof config.type != "string" || (
            (!["GET","POST","DELETE","PUT","PATCH"].includes(this.defaults.type.toLocaleUpperCase()))
        )){
            config.type=this.defaults.type;
        };
        // timeout 请求超时时间
        if(typeof config.timeout != "number" || isNaN(config.timeout)){
            config.timeout=this.defaults.timeout;
        };
        // dataType 返回参数类型
        if(typeof config.dataType != "string" || (
            config.dataType.toLocaleUpperCase() != "STRING" &&
            config.dataType.toLocaleUpperCase() != "XML" &&
            config.dataType.toLocaleUpperCase() != "HTML" &&
            config.dataType.toLocaleUpperCase() != "JSON" &&
            config.dataType.toLocaleUpperCase() != "BLOB" &&
            config.dataType.toLocaleUpperCase() != "JSONP"
        )){
            config.dataType=this.defaults.dataType;
        };
        // jsonpCallback 跨域回调方法名称
        if(typeof config.jsonpCallback != "string"){
            config.jsonpCallback=this.defaults.jsonpCallback;
        };
        // headers 请求头配置
        if(typeof config.headers != "object"){
            config.headers=this.defaults.headers;
        }else{ //如果配置的config有headers则将defaults的追加进来
            let obj=config.headers;
            config.headers={};
            Object.assign(config.headers,this.defaults.headers,obj);
        };
        // contentType 配置
        if(typeof config.contentType != "string" && config.contentType !== false){
            config.contentType=this.defaults.contentType;
        };
        // processData 配置
        if(typeof config.processData != "boolean"){
            config.processData=this.defaults.processData;
        };
        // cache 缓存配置
        if(typeof config.cache != "boolean"){
            config.cache=this.defaults.cache;
        };
        // async 异步
        if(typeof config.async != "boolean"){
            config.async=this.defaults.async;
        };
        // withCredentials 跨站点访问控制
        if(typeof config.withCredentials != "boolean"){
            config.withCredentials=this.defaults.withCredentials;
        };
        // beforeSend 请求发送前
        if(typeof config.beforeSend != "function"){
            config.beforeSend=this.defaults.beforeSend;
        };
        // complete 请求完成
        if(typeof config.complete != "function"){
            config.complete=this.defaults.complete;
        };
        // onProgress 请求进度
        if(typeof config.onProgress != "function"){
            config.onProgress=this.defaults.onProgress;
        };
        // cancelRequest 取消请求
        if(typeof config.cancelRequest != "function"){
            config.cancelRequest=this.defaults.cancelRequest;
        };
        // beforeRequest 请求发送之前对数据进行处理
        if(typeof config.beforeRequest != "function"){
            config.beforeRequest=this.defaults.beforeRequest;
        };
        // beforeResponse 请求响应前对响应结果进行处理
        if(typeof config.beforeResponse != "function"){
            config.beforeResponse=this.defaults.beforeResponse;
        };
        return config;
    };
    // 将json类型的数据转为&拼接的字符串
    _getParams(data){
        let arr=[];
        for(let param in data){
            arr.push(encodeURIComponent(param)+"="+encodeURIComponent(data[param]));
        };
        return arr.join("&");
    };
    // post请求
    post(url,data){
        let config={
            url,
            data,
            type:"POST"
        };
        return this.create(config);
    };
    // put请求
    put(url,data){
        let config={
            url,
            data,
            type:"PUT"
        };
        return this.create(config);
    };
    // patch请求
    patch(url,data){
        let config={
            url,
            data,
            type:"PATCH"
        };
        return this.create(config);
    };
    // get请求
    get(url,data){
        let config={
            url,
            data,
            type:"GET"
        };
        return this.create(config);
    };
    // delete请求
    delete(url,data){
        let config={
            url,
            data,
            type:"DELETE"
        };
        return this.create(config);
    };
};

export default Qilinx;